package com.cdks.wuxiu.api.service.mysql;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cdks.wuxiu.api.component.constant.Constant;
import com.cdks.wuxiu.api.mapper.CallSheetInfoMapper;
import com.cdks.wuxiu.api.util.TimeUtils;
import com.cdks.wuxiu.entity.mysql.CallSheetInfo;
import com.cdks.wuxiu.entity.mysql.UserBaseInfo;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Service;


/**
 * 通话信息表 服务实现类
 */
@Slf4j
@Service
public class CallSheetInfoServiceImpl extends ServiceImpl<CallSheetInfoMapper, CallSheetInfo> implements CallSheetInfoService {

    @Override
    public CallSheetInfo getByUcid(String ucid) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, ucid);

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getByUcidWithCaller(String ucid, long caller) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, ucid)
                        .eq(CallSheetInfo::getCallerId, caller);

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getByUcidWithAnswer(String ucid, long answer) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, ucid)
                        .eq(CallSheetInfo::getAnswerId, answer);

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getByUcidWithAnyUser(String ucid, long userId) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, ucid);
        wrapper.last(" AND ((callerId=" + userId + ") OR (answerId=" + userId + "))");

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getBusyCallByCaller(long caller) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getCallerId, caller)
                        .lt(CallSheetInfo::getStatus, Constant.CALL_STATUS_STOPPED);

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getBusyCallByAnswer(long answer) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getAnswerId, answer)
                        .lt(CallSheetInfo::getStatus, Constant.CALL_STATUS_STOPPED);

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getBusyCallAnyUser(long caller, long answer) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();

        wrapper.lambda().lt(CallSheetInfo::getStatus, Constant.CALL_STATUS_STOPPED);
        wrapper.last(" AND ((callerId=" + caller + ") OR (answerId=" + answer + "))");

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getStartedCallAnyUser(long caller, long answer) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getStatus, Constant.CALL_STATUS_STARTED);
        wrapper.last(" AND ((callerId=" + caller + ") OR (answerId=" + answer + "))");

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getStartedCallBothUser(long caller, long answer) {
        List<Long> ids  = Arrays.asList(caller, answer);
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getStatus, Constant.CALL_STATUS_STARTED)
                        .in(CallSheetInfo::getCallerId, ids)
                        .in(CallSheetInfo::getAnswerId, ids);

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public CallSheetInfo getPayedCallBothUser(long caller, long answer) {
        List<Long> ids  = Arrays.asList(caller, answer);
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().gt(CallSheetInfo::getDuration, 0)
                        .in(CallSheetInfo::getCallerId, ids)
                        .in(CallSheetInfo::getAnswerId, ids);
        wrapper.last(" LIMIT 1");

        return baseMapper.selectOne(wrapper);
    }

    @Override
    public List<CallSheetInfo> getFreeCallByCaller(long caller) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().gt(CallSheetInfo::getDuration, 0)
                        .gt(CallSheetInfo::getFreeNum, 0)
                        .eq(CallSheetInfo::getCallerId, caller)
                        .ge(CallSheetInfo::getCreateTime, (TimeUtils.getTimeSecond() / 86400) * 86400 - 28800);

        return baseMapper.selectList(wrapper);
    }

    @Override
    public int callout(CallSheetInfo sheet) {
        int ret  = baseMapper.insert(sheet);
        if (ret <= 0)
        {
            log.error("call callout insert db failed: " + JSONUtil.toJsonStr(sheet) + ", ret = " + ret);

            return -1;
        }
        
        return 0;
    }

    @Override
    public int ringing(CallSheetInfo sheet) {
        UpdateWrapper<CallSheetInfo> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, sheet.getUcid())
                        .eq(CallSheetInfo::getStatus, Constant.CALL_STATUS_WAITING);

        int ret  = baseMapper.update(sheet, wrapper);
        if (ret == 1)
        {
            return 0;
        }
        else
        {
            log.error("call ringing update db failed: " + JSONUtil.toJsonStr(sheet) + ", ret = " + ret);
        }

        return -1;
    }

    @Override
    public int answer(CallSheetInfo sheet) {
        UpdateWrapper<CallSheetInfo> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, sheet.getUcid())
                        .eq(CallSheetInfo::getStatus, Constant.CALL_STATUS_WAITING);

        int ret  = baseMapper.update(sheet, wrapper);
        if (ret == 1)
        {
            return 0;
        }
        else
        {
            log.error("call answer update db failed: " + JSONUtil.toJsonStr(sheet) + ", ret = " + ret);
        }

        return -1;
    }

    @Override
    public int keepAlive(CallSheetInfo sheet, long payedCost) {
        UpdateWrapper<CallSheetInfo> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, sheet.getUcid())
                        .eq(CallSheetInfo::getPayCost, payedCost)
                        .eq(CallSheetInfo::getStatus, Constant.CALL_STATUS_STARTED);

        int ret  = baseMapper.update(sheet, wrapper);
        if (ret == 1)
        {
            return 0;
        }

        return -1;
    }

    @Override
    public int hangup(CallSheetInfo sheet) {
        UpdateWrapper<CallSheetInfo> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, sheet.getUcid())
                        .lt(CallSheetInfo::getStatus, Constant.CALL_STATUS_STOPPED);

        int ret  = baseMapper.update(sheet, wrapper);
        if (ret == 1)
        {
            return 0;
        }

        return -1;
    }

    @Override
    public int update(CallSheetInfo sheet) {
        UpdateWrapper<CallSheetInfo> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, sheet.getUcid());

        int ret  = baseMapper.update(sheet, wrapper);
        if (ret == 1)
        {
            return 0;
        }

        return -1;
    }

    @Override
    public UserBaseInfo selectCallee(long selfId, int userType, int role, int sex, int balance, Set<Long> excludes) {
        //where：1、同类型账号，3、账号状态正常，4、勿扰状态关闭，5、限定性别，6、限定收费单价，7、排除指定用户（有接听记录、10分钟内有拒接主叫记录），8、空闲，9、不小于指定角色
        //order：距离上一次被叫时间间隔最长
        //limit：1
        return baseMapper.selectCallee(selfId, userType, role, sex, balance, excludes);
    }

    @Override
    public UserBaseInfo getRandAnswer(long selfId, int userType, int role, int sex, int balance, Set<Long> excludes) {
        //where：1、同类型账号，3、账号状态正常，4、勿扰状态关闭，5、限定性别，6、限定收费单价，7、排除指定用户（自己、10分钟内有成功通话或拒接），8、空闲，9、不小于指定角色
        //order：距离上一次被叫时间间隔最长
        //limit：1
        return baseMapper.getRandAnswer(selfId, userType, role, sex, balance, excludes);
    }

    @Override
    public List<UserBaseInfo> getNoticeCallee(long userId, int userType, int role, Set<String> excludes) {
        //where：1、同类型账号，2、账号状态正常，3、排除指定用户（黑名单、10分钟内有呼叫记录），4、离线，5、优先级大于0，6、已认证用户， 7、不小于指定角色
        //order：登录时间降序
        //limit：30        
        return baseMapper.getNoticeCallee(userId, userType, role, excludes);
    }

    @Override
    public List<UserBaseInfo> getRandCallee(long selfId, int userType, int role, int sex) {
        //where：1、同类型账号，2、账号状态正常，3、排除指定用户（自己、黑名单、10分钟内有成功通话或拒接），4、离线或空闲，5、优先级大于0，6、限定性别， 7、不小于指定角色
        //order：登录时间降序
        //limit：30
        return baseMapper.getRandCallee(selfId, userType, role, sex);
    }

    @Override
    public int record(String ucid, String info) {
        int ret  = baseMapper.record(ucid, info);
        if (ret <= 0)
        {
            log.error("call record update db failed: " + ucid + ", ret = " + ret);

            return -1;
        }
        
        return 0;
    }

    @Override
    public int setSipId(String ucid, String sipId) {
        int ret  = baseMapper.setSipId(ucid, sipId);
        if (ret <= 0)
        {
            log.error("call setSipId update db failed: " + ucid + ", ret = " + ret);

            return -1;
        }
        
        return 0;
    }

    @Override
    public CallSheetInfo getBySipId(String sipId) {
        QueryWrapper<CallSheetInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getSipId, sipId);

        CallSheetInfo sheet  = baseMapper.selectOne(wrapper);
        if (sheet == null)
        {
            log.error("call getBySipId() failed: sipId = " + sipId);
        }

        return sheet;
    }

    @Override
    public int updateSheetByStatus(CallSheetInfo sheet, int status) {
        UpdateWrapper<CallSheetInfo> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(CallSheetInfo::getUcid, sheet.getUcid())
                        .eq(CallSheetInfo::getStatus, status);

        int ret  = baseMapper.update(sheet, wrapper);
        if (ret == 1)
        {
            return 0;
        }

        return -1;
    }
}
